/**
 * @class CircularBuffer
 * @brief A thread-safe, fixed-size, circular buffer implementation with optional duplicate checks.
 *
 * This class provides a thread-safe, circular buffer implementation with the following features:
 * - Fixed-size buffer with optional dynamic resizing.
 * - Push and emplace methods for adding elements to the buffer.
 * - Thread-safe pop and wait_and_pop methods for removing elements from the buffer.
 * - Option to allow or disallow duplicate elements.
 * - Thread-safe utility methods for checking buffer capacity, size, and emptiness.
 * - Clear method to reset the buffer state.
 *
 * @tparam T The type of elements stored in the buffer.
 */
#pragma once
#include <vector>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <algorithm>
#include <iostream>
#include <type_traits>
template<typename T, typename = void>
struct has_equal_operator : std::false_type {};

template<typename T>
struct has_equal_operator<T, std::void_t<decltype(std::declval<T>() == std::declval<T>())>> : std::true_type {};

template<typename T>
constexpr bool has_equal_operator_v = has_equal_operator<T>::value;
#define allow_duplicates_switch 1
template<typename T>
class CircularBuffer {
public:
    explicit CircularBuffer(size_t capacity = 0, bool limit_size = false, bool replace_oldest = false)
        : m_capacity(capacity), m_buffer(m_capacity), m_head(0), m_tail(0), m_size(0),
        m_limit_size(limit_size), m_replace_oldest(replace_oldest) {
//          std::cout << "CircularBuffer build" << std::endl;
    }
    //get front element
    T& front(){
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_buffer[m_head];
    }
    //get back element
    T& back(){
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_buffer[m_tail];
    }


    /**
     * @brief 向循环缓冲区添加元素（线程安全）
     *
     * @tparam U 元素类型
     * @param t 要添加的元素左值引用。
     * @return 如果成功添加元素，返回 true；否则返回 false
     */
    template<typename U>
    bool push(U* t) {
        return _push_internal_(*t);
    }
    /**
     * @brief 向循环缓冲区添加元素（线程安全）
     *
     * @tparam U 元素类型
     * @param t 要添加的元素（右值引用）,可以是左值引用或右值引用。
     * @return 如果成功添加元素，返回 true；否则返回 false
     */
    template<typename U>
    bool push(U&& t) {
        return _push_internal_(std::forward<U>(t));
    }
    /**
     * @brief 添加一个元素到队列中，使用构造函数参数
     *
     * 该函数创建一个 T 类型的对象，并将其添加到队列中。当队列容量不足时，根据 m_limit_size 的设置，可能会自动扩容。
     * 如果不允许重复元素，当要插入的元素已经在队列中时，将不执行插入操作。
     *
     * @tparam Args 传递给 T 构造函数的参数类型
     * @param args 传递给 T 构造函数的参数
     * @return 如果元素成功添加到队列，返回 true；否则返回 false
     */
    template<typename... Args>
    bool emplace(Args&&... args) {
        T t(std::forward<Args>(args)...);
        return _push_internal_(std::move(t));
    }

    /**
     * 尝试从队列中弹出一个元素。
     *
     * @tparam Rep 时间表示 (默认为 int64_t)
     * @tparam Period 时间单位 (默认为 std::ratio<1>，表示秒)
     * @param t 引用，用于保存弹出的元素
     * @param timeout 超时时间 (默认为 std::chrono::duration<Rep, Period>::zero()，表示立即尝试获取数据)
     * @return 如果成功弹出元素，返回 true；否则返回 false
     *
     * 当 timeout 为零时 (默认)，函数将立即尝试获取数据，不会等待。
     * 当 timeout 大于零时，函数将最多尝试等待指定的超时时间。
     * 如果在超时时间内队列中仍无元素可弹出，函数将立即返回 false。
     */
    template<typename Duration = std::chrono::microseconds >
    bool pop(T& t, const Duration& timeout = Duration::zero()) {
        return _pop_internal_(t, timeout);
    }
    T& pop(){
        std::unique_lock<std::mutex> lock(m_mutex);
        T& t = m_buffer[m_head];
        m_head = (m_head + 1) % m_capacity;
        --m_size;
        return t;
    }

    /**
     * 在指定的超时时间内等待并尝试从循环缓冲区中弹出一个元素。
     *
     * @tparam Rep 表示时间的整数类型。
     * @tparam Period 表示时间单位的比率类型。
     * @param[out] t 用于存储弹出元素的引用。
     * @param[in] timeout 等待超时时间，默认为 -1 微妙（无限等待）。
     * @return 如果成功从缓冲区中弹出元素，则返回 true，否则返回 false。
     */
    template<typename Duration = std::chrono::microseconds >
    bool wait_and_pop(T &t, const Duration& timeout = std::chrono::microseconds(-1)) {
        return _pop_internal_(t, timeout);
    }
    /**
     * @brief 设置是否限制缓冲区大小
     * @param limit_size 如果为 true，则限制缓冲区大小；否则，不限制
     */
    void set_limit_size(bool limit_size) {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_limit_size = limit_size;
    }
    /**
     * @brief 设置是否允许缓冲区中的元素重复
     * @param allow_duplicates 如果为 true，则允许元素重复；否则，不允许
     */
    void set_allow_duplicates(bool allow_duplicates) {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_allow_duplicates = allow_duplicates;
    }
    /**
     * @brief 获取当前队列的容量
     * @return 当前队列的容量
     */
    size_t capacity() const {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_capacity;
    }
    /**
     * @brief 判断队列是否为空
     * @return 如果队列为空返回 true，否则返回 false
     */
    bool empty() const {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_size == 0;
    }

    /**
     * @brief 调整缓冲区的容量
     * @param new_capacity 新的缓冲区容量
     */
    void resize(size_t new_capacity){
        std::unique_lock<std::mutex> lock(m_mutex);
        _resize_(new_capacity);
    }

    /**
     * @brief 获取队列中元素的数量
     * @return 队列中元素的数量
     */
    size_t size() const {
        std::unique_lock<std::mutex> lock(m_mutex);
        return m_size;
    }
    /**
     * @brief 清空缓冲区，移除所有元素
     */
    void clear() {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_head = 0;
        m_tail = 0;
        m_size = 0;
    }

private:
    size_t m_capacity;                 // 缓冲区的容量
    std::vector<T> m_buffer;           // 存储元素的缓冲区
    size_t m_head, m_tail, m_size;     // 头部、尾部和缓冲区的大小
    bool m_limit_size;                 // 是否限制缓冲区大小
    bool m_allow_duplicates;           // 是否允许缓冲区中的元素重复
    mutable std::mutex m_mutex;        // 互斥锁，用于线程安全访问缓冲区
    std::condition_variable m_cv;      // 条件变量，用于线程间通信
    bool m_replace_oldest;             // 当缓冲区已满时，是否替换最旧的元素
    /**
     * @brief 内部函数，向缓冲区添加元素（线程安全）
     *
     * 这个函数尝试将元素添加到缓冲区。如果缓冲区已满，它的行为取决于 m_limit_size 和 m_replace_oldest 的设置。
     * 如果 m_limit_size 为 true，且 m_replace_oldest 为 true，它将替换缓冲区中的最旧元素。
     * 如果 m_limit_size 为 true，且 m_replace_oldest 为 false，它将返回 false，表示无法添加元素。
     * 如果 m_limit_size 为 false，它将扩大缓冲区的容量，然后添加元素。
     *
     * @param t 要添加的元素
     * @return 如果成功添加元素，返回 true；否则返回 false
     *
     * @param t 要添加的元素
     * @return 如果成功添加元素，返回 true；否则返回 false
     */
    bool _push_internal_(T& t);
    /**
     * @brief 内部函数，尝试从缓冲区中弹出一个元素，可设置超时时间
     *
     * @tparam Duration 时间单位，默认为微秒
     * @param[out] t 用于存储弹出元素的引用
     * @param[in] timeout 等待超时时间，默认为 0 微秒（立即返回）
     * @return 如果成功从缓冲区中弹出元素，则返回 true，否则返回 false
     *
     * 当 timeout 为零时，函数将立即尝试获取数据，不会等待。
     * 当 timeout 大于零时，函数将最多尝试等待指定的超时时间。
     * 如果在超时时间内队列中仍无元素可弹出，函数将立即返回 false。
     */
    template<typename Duration = std::chrono::microseconds>
    bool _pop_internal_(T& t, const Duration& timeout);
    /**
     * @brief 调整循环缓冲区的容量
     *
     * 如果新容量等于当前容量，则不进行任何操作。
     * 否则，将元素移动到新缓冲区中，保留最新的元素并移除最旧的元素。
     * 最后更新头、尾、容量和缓冲区。
     *
     * @param new_capacity 新的缓冲区容量
     */
    void _resize_(size_t new_capacity);
};
/**
 * @class CircularBuffer
 * @brief A thread-safe, fixed-size, circular buffer implementation with optional duplicate checks.
 *
 * This class provides a thread-safe, circular buffer implementation with the following features:
 * - Fixed-size buffer with optional dynamic resizing.
 * - Push and emplace methods for adding elements to the buffer.
 * - Thread-safe pop and wait_and_pop methods for removing elements from the buffer.
 * - Option to allow or disallow duplicate elements.
 * - Thread-safe utility methods for checking buffer capacity, size, and emptiness.
 * - Clear method to reset the buffer state.
 *
 * @tparam T The type of elements stored in the buffer.
 */

    /**
     * @brief 内部函数，向缓冲区添加元素（线程安全）
     *
     * 这个函数尝试将元素添加到缓冲区。如果缓冲区已满，它的行为取决于 m_limit_size 和 m_replace_oldest 的设置。
     * 如果 m_limit_size 为 true，且 m_replace_oldest 为 true，它将替换缓冲区中的最旧元素。
     * 如果 m_limit_size 为 true，且 m_replace_oldest 为 false，它将返回 false，表示无法添加元素。
     * 如果 m_limit_size 为 false，它将扩大缓冲区的容量，然后添加元素。
     *
     * @param t 要添加的元素
     * @return 如果成功添加元素，返回 true；否则返回 false
     *
     * @param t 要添加的元素
     * @return 如果成功添加元素，返回 true；否则返回 false
     */
template<typename T>
bool CircularBuffer<T>::_push_internal_(T& t) {
        // 使用互斥锁来确保线程安全
        std::unique_lock<std::mutex> lock(m_mutex);
        // 如果不允许重复值且值已存在，直接返回 false
        if (!m_allow_duplicates) {
            if constexpr (has_equal_operator_v<T>) {
                for (const auto& elem : m_buffer) {
                if (elem == t) {
                    return false;
                }
             }
            } else {
            //   std::cout <<"not deal qual " <<std::endl;
                // T 没有定义 == 操作符
            }
        }
        if (m_limit_size && (m_size >= m_capacity)) {
            if (m_replace_oldest) {
                // 替换最旧的元素
                m_buffer[m_head] = t;
                // 更新循环缓冲区的头部
                m_head = (m_head + 1) % m_capacity;
                // 更新循环缓冲区的尾部
                m_tail = m_head;
            } else {
                // 如果限制大小且不允许替换最旧的元素，则返回 false
                return false;
            }
        }else if (!m_limit_size && m_size >= m_capacity) {
            // 如果没有限制大小且缓冲区已满，扩大缓冲区容量
            _resize_(m_capacity * 2);

            // 将元素添加到缓冲区的尾部
            m_buffer[m_tail] = t;
            // 更新循环缓冲区的尾部和大小
            m_tail = (m_tail + 1) % m_capacity;
            ++m_size;
        } else {
            m_buffer[m_tail] = t;
            // 更新循环缓冲区的尾部和大小
            m_tail = (m_tail + 1) % m_capacity;
            ++m_size;
        }

        // 唤醒等待线程
        m_cv.notify_one();

        // 如果成功将元素添加到缓冲区，返回 true
        return true;
}
template<typename T>
void CircularBuffer<T>:: _resize_(size_t new_capacity) {
    // 如果新容量小于或等于当前容量，则不进行任何操作
    if (new_capacity == m_capacity || new_capacity == 0 ) {
        std::cout<< "new_capacity-m_capacity:"<<new_capacity<<std::endl;
        return;
    }
    try {
        // 创建新的缓冲区
        if(m_buffer.size() == 0){
            m_buffer.resize(new_capacity);
            m_capacity = new_capacity;
        }
        else{
            std::vector<T> new_buffer(new_capacity);
            size_t new_tail = 0;

            // 从尾部开始遍历，保留最新的元素，移除最旧的元素
            size_t elements_to_copy = std::min(m_size, new_capacity);
            size_t old_tail = (m_tail + m_capacity - 1) % m_capacity;
            for (size_t j = 0; j < elements_to_copy; ++j) {
                size_t old_index = (old_tail + m_capacity - j) % m_capacity;
                size_t new_index = (new_capacity - j - 1) % new_capacity;

                new_buffer[new_index] = std::move(m_buffer[old_index]);
                new_tail = (new_tail + 1) % new_capacity;
            }
            // 更新头、尾、容量和缓冲区
            m_capacity = new_capacity;
            m_buffer = std::move(new_buffer);
            m_head = new_tail;
            m_tail = 0;
            m_size = elements_to_copy;
        }
    } catch (const std::bad_alloc& e) {
        std::cerr << "Memory allocation failed: " << e.what() << std::endl;
        // 你可以在这里添加更多的错误处理代码，例如回滚操作，或者重新抛出异常
    } catch (const std::exception& e) {
        // 捕获其他类型的标准异常
        std::cerr << "Exception: " << e.what() << std::endl;
    } catch (...) {
        // 捕获所有其他类型的异常
        std::cerr << "Unknown exception caught" << std::endl;
    }
}


template<typename T>
template<typename Duration>
bool CircularBuffer<T>::_pop_internal_(T& t, const Duration& timeout) {
    // 使用互斥锁来确保线程安全
    std::unique_lock<std::mutex> lock(m_mutex);

    if(m_size == 0){
        // 如果超时时间为零且缓冲区为空，立即返回 false
        if (timeout == Duration::zero()) {
            return false;
        }
        // 如果超时时间小于零，等待直到缓冲区中有元素
        else if (timeout < Duration::zero()) {
            m_cv.wait(lock, [this]() { return m_size > 0; });
        }
        // 如果超时时间大于零，等待指定的超时时间，如果超时且缓冲区仍为空，返回 false
        else {
            if (!m_cv.wait_for(lock, timeout, [this]() { return m_size > 0; })) {
                return false;
            }
        }
        if (m_size == 0) {
            return false;
        }
    }
    // 将缓冲区的首个元素移动到给定引用
    t = std::move(m_buffer[m_head]);
    // 更新循环缓冲区的头部和大小
    m_head = (m_head + 1) % m_capacity;
    --m_size;
    // 如果成功弹出元素，返回 true
    return true;
}
